package com.atguigu.tingshu.album.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.order.client.OrderInfoFeignClient;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserClientFeign;
import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
import com.atguigu.tingshu.vo.album.TrackInfoVo;
import com.atguigu.tingshu.vo.album.TrackListVo;
import com.atguigu.tingshu.vo.album.TrackStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import com.tencentcloudapi.vod.v20180717.models.MediaBasicInfo;
import com.tencentcloudapi.vod.v20180717.models.MediaInfo;
import com.tencentcloudapi.vod.v20180717.models.MediaMetaData;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    private TrackInfoMapper trackInfoMapper;
    private VodConstantProperties vodConstantProperties;
    private VodService vodService;
    private TrackStatMapper trackStatMapper;
    private AlbumInfoMapper albumInfoMapper;
    private UserClientFeign userClientFeign;
    private OrderInfoFeignClient orderInfoFeignClient;


    /**
     * 创作音频 -声音上传
     *
     * @param file 文件
     * @return
     */
    @SneakyThrows
    @Override
    public Object uploadTrack(MultipartFile file) {
        // 将用户上传的音频存储到本地
        String tempPath = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(), file);
        // 创建云点播的客户端对象
        VodUploadClient client = new VodUploadClient(vodConstantProperties.getSecretId(), vodConstantProperties.getSecretKey());
        // 构造上传请求对象
        VodUploadRequest request = new VodUploadRequest();
        request.setMediaFilePath(tempPath);
        // 本地文件上传到腾讯云
        VodUploadResponse response = client.upload(vodConstantProperties.getRegion(), request);
        // 获取文件唯一标识
        String fileId = response.getFileId();
        // 获取文件的播放地址
        String mediaUrl = response.getMediaUrl();
        // 包装返回结果
        JSONObject result = new JSONObject();
        result.put("mediaFileId", fileId);
        result.put("mediaUrl", mediaUrl);
        // 返回声音的播放地址信息;
        return result;
    }

    /**
     * 创作音频 - 保存声音信息
     *
     * @param trackInfoVo 声音信息
     */
    @Override
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {
        // 声明DO
        TrackInfo trackInfo = new TrackInfo();
        // 属性转移
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        trackInfo.setUserId(1L);
        // 补全声音的详细信息 查询腾讯云的声音详细信息
        MediaInfo mediaInfo = vodService.getTrackDetailInfo(trackInfoVo.getMediaFileId());
        // 获取声音的类型
        MediaBasicInfo basicInfo = mediaInfo.getBasicInfo();
        String type = basicInfo.getType();
        trackInfo.setMediaType(type);
        // 声音的播放地址
        String mediaUrl = basicInfo.getMediaUrl();
        trackInfo.setMediaUrl(mediaUrl);
        // 获取声音的时长:秒
        MediaMetaData metaData = mediaInfo.getMetaData();
        Float duration = metaData.getDuration();
        trackInfo.setMediaDuration(new BigDecimal(duration.toString()));
        // 获取声音的大小
        Long size = metaData.getSize();
        trackInfo.setMediaSize(size);
        // 声音的地址
        // 查询数据库中当前这个专辑的声音的order_num的最大值到几了
        Integer orderNum = trackInfoMapper.selectTrackMaxOrderNum(trackInfoVo.getAlbumId());
        // 判断
        if (orderNum == null) {
            orderNum = 0;
        }
        trackInfo.setOrderNum(orderNum + 1);
        // 保存声音到数据库
        if (!save(trackInfo)) {
            throw new GuiguException(201, "保存声音数据失败");
        }
        // 获取声音的id
        Long trackId = trackInfo.getId();
        // 初始化声音的统计信息
        initTrackStat(trackId);
        // 查询专辑的数据
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        if (albumInfo == null) {
            throw new GuiguException(201, "专辑不存在,无法添加声音");
        }
        // 专辑的声音数量+1
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        albumInfoMapper.updateById(albumInfo);
    }

    /**
     * 分页查询当前用户声音列表
     *
     * @param trackInfoQuery
     * @param page
     * @return
     */
    @Override
    public Object findUserTrackPage(TrackInfoQuery trackInfoQuery, Page<TrackListVo> page) {
        return trackInfoMapper.selectTrackInfo(trackInfoQuery, page);
    }

    /**
     * 声音管理 - 删除声音
     *
     * @param trackId 声音id
     */
    @Override
    public void removeTrackInfo(Long trackId) {
        // 条件拼接
        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getUserId, 1L)
                .eq(TrackInfo::getId, trackId);

        // 查询声音的详细信息
        TrackInfo trackInfo = getOne(wrapper);
        if (trackInfo == null) {
            throw new GuiguException(201, "声音不存在");
        }
        // 删除声音表的数据
        if (!removeById(trackId)) {
            throw new GuiguException(201, "删除声音失败");
        }
        // 删除统计表
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>()
                .eq(TrackStat::getTrackId, trackId));
        // 专辑的包含声音的数量-1
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);
        // 云点播的文件删除掉
        vodService.removeFile(trackInfo.getMediaFileId());
    }

    /**
     * 修改声音
     *
     * @param trackInfoVo 声音信息
     * @param trackId     声音id
     */
    @Override
    public void updateTrackInfo(TrackInfoVo trackInfoVo, Long trackId) {
        // 查询声音的数据
        TrackInfo trackInfo = getOne(new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getUserId, 1L)
                .eq(TrackInfo::getId, trackId));
        if (trackInfo == null) {
            throw new GuiguException(201, "声音不存在!");
        }
        // 存在判断声音文件有没有变化
        String oldMediaFileId = trackInfo.getMediaFileId();
        // 获取本次的文件id
        String newMediaFileId = trackInfoVo.getMediaFileId();
        // 属性替换
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        if (!oldMediaFileId.equals(newMediaFileId)) {
            // 有变化,删除旧的
            vodService.removeFile(oldMediaFileId);
            // 查询新的信息
            MediaInfo mediaInfo =
                    vodService.getTrackDetailInfo(newMediaFileId);
            // 使用新的信息替换旧的信息: 大小 时长 播放地址 类型
            MediaMetaData metaData = mediaInfo.getMetaData();
            trackInfo.setMediaDuration(new BigDecimal(metaData.getDuration().toString()));
            trackInfo.setMediaSize(metaData.getSize());
            MediaBasicInfo basicInfo = mediaInfo.getBasicInfo();
            trackInfo.setMediaUrl(basicInfo.getMediaUrl());
            trackInfo.setMediaType(basicInfo.getType());
        }
        // 修改声音的数据
        updateById(trackInfo);
    }

    /**
     * 分页查询指定专辑的声音列表
     *
     * @param albumId 专辑id
     * @param page    当前页
     * @param size    每页显示记录数
     * @return 声音列表
     */
    @Override
    public Object findAlbumTrackPage(Long albumId, Integer page, Integer size) {
        Object result = null;
        // 查询专辑数据是否存在
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "专辑不存在，声音不存在!");
        }
        // 获取专辑的收费类型: 0101-免费、0102-vip免费、0103-付费
        String payType = albumInfo.getPayType();
        // 根据不同的类型进行处理
        switch (payType) {
            // 免费-专辑
            case "0101" -> result = freeAlbum(albumId, page, size);
            // vip免费-专辑
            case "0102" -> result = vipAlbum(albumInfo, page, size);
            // 付费
            case "0103" -> result = payAlbum(albumInfo, page, size);
        }
        // 返回
        return result;
    }

    /**
     * 获取声音统计信息
     *
     * @param trackId 声音id
     * @return 声音统计vo
     */
    @Override
    public Object getTrackStatVo(Long trackId) {

        // 1.根据声音id获取声音统计信息
        List<TrackStat> trackStats = trackStatMapper.selectList(new LambdaQueryWrapper<TrackStat>()
                .eq(TrackStat::getTrackId, trackId));
        // 转map
        Map<String, Integer> trackStatMap = trackStats.stream().collect(Collectors.toMap(
                key -> key.getStatType(),
                value -> value.getStatNum()
        ));

        // 2.封装数据
        TrackStatVo trackStatVo = new TrackStatVo();
        trackStatVo.setPlayStatNum(trackStatMap.get("0701"));
        trackStatVo.setCollectStatNum(trackStatMap.get("0702"));
        trackStatVo.setPraiseStatNum(trackStatMap.get("0703"));
        trackStatVo.setCommentStatNum(trackStatMap.get("0704"));

        // 3.返回
        return trackStatVo;
    }

    /**
     * 获取用户指定购买和可购买未购买的声音列表
     *
     * @param trackId 声音id
     * @return 声音列表
     */
    @Override
    public Object findUserTrackPaidList(Long trackId) {
        // 查询当前声音的详细信息
        TrackInfo trackInfo = getById(trackId);
        // 获取专辑id
        Long albumId = trackInfo.getAlbumId();

        // 查询专辑的详情
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        // 获取当前选中这个声音之后的声音
        List<TrackInfo> trackInfoList = list(new LambdaQueryWrapper<TrackInfo>()
                .ge(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                .eq(TrackInfo::getAlbumId, albumId));
        // 1.可能包含用户买过的
        Map<String, Object> userPaidTrackMap = userClientFeign.getUserPaidTrack(albumId, AuthContextHolder.getUserId());
        // 2.可能包含用户未支付
        Map<String, Object> userTrackOrderMap = orderInfoFeignClient.getUserTrackOrderInfo(AuthContextHolder.getUserId());
        // 过滤买过的和未支付的 保存可以购买的 限制返回50条
        List<TrackInfo> trackInfoListNew = trackInfoList.stream()
                .filter(f -> userPaidTrackMap.get(f.getId().toString()) == null &&
                        userTrackOrderMap.get(f.getId().toString()) == null)
                .limit(50)
                .collect(Collectors.toList());
        // 获取声音的单价
        BigDecimal price = albumInfo.getPrice();

        // 最终结果集初始化
        List<JSONObject> result = new ArrayList<>();

        // 包装本集声音信息
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name", "本集");
        jsonObject.put("trackCount", "1");
        jsonObject.put("price", price);
        result.add(jsonObject);

        // 包装后面剩余集数的声音信息
        int size = trackInfoListNew.size();
        if (size > 1) {
            // 展示几个标签
            int count = size % 10 == 0 ? size / 10 : size / 10 + 1;
            // 包装标签: 10集 20集 30集 40集 50集
            for (int i = 1; i <= count; i++) {
                jsonObject = new JSONObject();
                // 当前的标签集数
                int flag = i * 10;
                // 和真实剩余集数对比
                if (flag > size) {
                    jsonObject.put("name", "后" + size + "集");
                    jsonObject.put("trackCount", size + "");
                    jsonObject.put("price", price.multiply(new BigDecimal(size)));
                } else {
                    jsonObject.put("name", "后" + i * 10 + "集");
                    jsonObject.put("trackCount", i * 10 + "");
                    jsonObject.put("price", price.multiply(new BigDecimal(i * 10)));
                }
                result.add(jsonObject);
            }
        }
        // 返回
        return result;
    }

    /**
     * 查询即将订单确认的声音信息
     *
     * @param trackId 声音id
     * @return 声音信息
     */
    @Override
    public JSONObject getTrackListAndPrice(Long trackId) {
        // 查询声音的详情
        TrackInfo trackInfo = getById(trackId);
        // 获取专辑的信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        // 获取专辑中当前声音后面的所有声音
        List<TrackInfo> trackInfoList = list(new LambdaQueryWrapper<TrackInfo>()
                .ge(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                .eq(TrackInfo::getAlbumId, albumInfo.getId()));
        // 包装返回结果
        JSONObject result = new JSONObject();
        result.put("trackInfoList", trackInfoList);
        result.put("price", albumInfo.getPrice());
        result.put("albumId", albumInfo.getId());
        // 返回
        return result;
    }

    /**
     * 免费专辑处理
     *
     * @return 声音列表
     */
    private Page<AlbumTrackListVo> freeAlbum(Long albumId, Integer page, Integer size) {
        // 查询这个专辑包含的声音的数据
        return trackInfoMapper.selectPageTrackInfoListByAlbumId(albumId, new Page<AlbumTrackListVo>(page, size));
    }

    /**
     * 专辑VIP免费处理
     *
     * @param albumInfo 专辑信息
     * @param page      当前页
     * @param size      每页显示记录数
     * @return 声音列表
     */
    private Page<AlbumTrackListVo> vipAlbum(AlbumInfo albumInfo, Integer page, Integer size) {
        // 查询声音数据
        Page<AlbumTrackListVo> result =
                trackInfoMapper.selectPageTrackInfoListByAlbumId(albumInfo.getId(),
                        new Page<AlbumTrackListVo>(page, size));

        // 获取专辑的免费集数
        Integer tracksForFree = albumInfo.getTracksForFree();

        // 获取用户的vip状态
        Integer vip = AuthContextHolder.getVip();

        if (vip.equals(0)) {
            // 不是vip: 全部收费
            List<AlbumTrackListVo> recordsNew = result.getRecords().stream().map(albumTrackListVo -> {
                // 修改为收费: 大于免费集数的
                if (albumTrackListVo.getOrderNum() > tracksForFree) {
                    // 收费
                    albumTrackListVo.setIsShowPaidMark(true);
                }
                // 返回
                return albumTrackListVo;
            }).collect(Collectors.toList());
            // 替换
            result.setRecords(recordsNew);
            // 返回
            return result;

        } else {
            // 是vip: 免费
            return result;
        }
    }

    /**
     * 付费专辑处理
     *
     * @param albumInfo 专辑信息
     * @param page      当前页
     * @param size      每页显示记录数
     * @return 声音列表
     */
    private Page<AlbumTrackListVo> payAlbum(AlbumInfo albumInfo, Integer page, Integer size) {
        // 获取免费集数
        Integer tracksForFree = albumInfo.getTracksForFree();

        // 查询声音数据
        Page<AlbumTrackListVo> result =
                trackInfoMapper.selectPageTrackInfoListByAlbumId(albumInfo.getId(),
                        new Page<AlbumTrackListVo>(page, size));

        // 获取用户id
        Long userId = AuthContextHolder.getUserId();

        // 获取价格类型: 0201-单集 0202-整专辑
        String priceType = albumInfo.getPriceType();

        // 如果是单集（0201）
        if (priceType.equals("0201")) {
            // 远程调用用户微服务 获取用户已购买的当前专辑的声音列表 Map<id, "1">
            Map<String, Object> userPaidTrackMap = userClientFeign.getUserPaidTrack(albumInfo.getId(), userId);
            // 本次查询到的声音进行对比
            List<AlbumTrackListVo> recordsNew = result.getRecords().stream().map(albumTrackListVo -> {
                // 处理的是为购买的
                if (userPaidTrackMap.get(albumTrackListVo.getTrackId().toString()) == null &&
                        albumTrackListVo.getOrderNum() > tracksForFree) {
                    albumTrackListVo.setIsShowPaidMark(true);
                }
                return albumTrackListVo;
            }).collect(Collectors.toList());
            // 覆盖
            result.setRecords(recordsNew);
            // 返回
            return result;

            // 如果是整专辑（0202）
        } else {
            // 判断用户是否已购买当前专辑
            if (userClientFeign.getUserPaidAlbum(albumInfo.getId(), userId)) {
                // 已购买: 免费 直接返回声音列表
                return result;
            } else {
                // 未购买: 免费以外全部付费
                List<AlbumTrackListVo> recordsNew = result.getRecords().stream().map(albumTrackListVo -> {
                    // 修改为收费: 大于免费集数的
                    if (albumTrackListVo.getOrderNum() > tracksForFree) {
                        // 收费
                        albumTrackListVo.setIsShowPaidMark(true);
                    }
                    // 返回
                    return albumTrackListVo;
                }).collect(Collectors.toList());
                // 替换
                result.setRecords(recordsNew);
                // 返回
                return result;
            }
        }
    }


    /**
     * 初始化声音的统计信息
     *
     * @param trackId 声音id
     */
    private void initTrackStat(Long trackId) {
        // 初始化Do
        TrackStat trackStat = new TrackStat();
        // 播放量
        trackStat.setTrackId(trackId);
        trackStat.setStatNum(0);
        trackStat.setStatType(SystemConstant.TRACK_STAT_PLAY);
        trackStatMapper.insert(trackStat);
        // 收藏量
        trackStat.setId(null);
        trackStat.setStatType(SystemConstant.TRACK_STAT_COLLECT);
        trackStatMapper.insert(trackStat);
        // 点赞量
        trackStat.setId(null);
        trackStat.setStatType(SystemConstant.TRACK_STAT_PRAISE);
        trackStatMapper.insert(trackStat);
        // 评论数
        trackStat.setId(null);
        trackStat.setStatType(SystemConstant.TRACK_STAT_COMMENT);
        trackStatMapper.insert(trackStat);
    }

}
